import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;


public class Server 
{	
	// Properties
	// Predefined Port for serverSocket
	public static final int PORT_NO = 4444;
	
	// Registry File
	public static final String USER_REG_PATH = "users.txt";
		
	// Registered Users and Their Connections
	private ArrayList<User> users;
	private ArrayList<Socket> sockets;
	private Vector<UserSession> userSessions;		// Using this because this is thread safe
	
	//Constructors
	public Server() 
	{
		// Init UserArrayList
		users = new ArrayList<User>();
		userSessions = new Vector<UserSession>();
		sockets = new ArrayList<Socket>();
		
		// Open users file
		BufferedReader fileIn = null;
		try 
		{
			fileIn = new BufferedReader(new FileReader(new File(USER_REG_PATH)));
		} 
		catch (FileNotFoundException e) 
		{
			System.out.println("Unable to Open: " + USER_REG_PATH);
			e.printStackTrace();
		}
		
		// Users Format
		// EveryLine Starts with u is a user line
		// u lines consists "u [username] [sharedDirectoryPath] [privateDirectoryPath]"
		// EveryLine Starts with f is a friend line
		// f lines consists "f [no] [no] [no] .... [no]
		// first number is the user secondary numbers is index of the list of friends
		String  line = null;
		try
		{
			while((line = fileIn.readLine()) != null)
			{
				if(line.charAt(0) == 'u')
				{
					// Found a u Line
					String[] lines = line.split("\\s");
					
					User u = new User();
					u.userName = lines[1];
					u.sharedFolderPath = "Files/" + lines[1] + "/Shared";
					u.privateFolderPath = "Files/" + lines[1] + "/Private";
					users.add(u);
				}
				else if(line.charAt(0) == 'f')
				{
					String[] lines = line.split("\\s");
					
					User currUser = users.get(Integer.parseInt(lines[1]));
					for(int i = 2; i < lines.length; i++)
						currUser.friends.add(users.get(Integer.parseInt(lines[i])));
					
				}
			}
			// Close File
			fileIn.close();
		}
		catch (IOException e)
		{
			System.out.println("Unable to read line from " + USER_REG_PATH);
			e.printStackTrace();
		}
		
		// DEBUG
		/*
		Iterator<User> i = users.iterator();
		while(i.hasNext())
		{
			User u = i.next();
			System.out.println(u.userName);
			System.out.println(u.privateFolderPath);
			System.out.println(u.sharedFolderPath);
			System.out.print("FRIENDS ");
			for(int  k = 0; k < u.friends.size(); k++)
				System.out.print(u.friends.get(k).userName + ", ");
			System.out.println();
		}
		*/
	}
	
	// Main Launch Method
	public void launch() 
	{
		try
		{
			// Create a new Server Socket
			ServerSocket listenSocket = new ServerSocket(PORT_NO);
			ServerSocket chatListenSocket = new ServerSocket(5555);
			
			// Run in Infinite loop
			boolean running = true;
			while(running)
			{
				// Listen Socket
				Socket connSock = listenSocket.accept();
				Socket chatSock = chatListenSocket.accept();
				sockets.add(chatSock);
				
				UserSession s = new UserSession(connSock);
				Thread t = new Thread(s);

                ChatServerThread thread = new ChatServerThread(this, chatSock);
                thread.start();
				if(s.validateUserProtocol(this, t))
				{
					userSessions.add(s);
					t.start();
				}
			}
			
			// Close ServerSocket
			listenSocket.close();
		}
		catch(IOException e)
		{
			System.out.println("Connection Problem.... Terminating");
			e.printStackTrace();
		}
		
	}
	
	public User findUser(String userName)
	{
		Iterator<User> i = users.iterator();
		while(i.hasNext())
		{
			User user = i.next();
			if (user.userName.equals(userName))
				return user;
		}
		return null;
	}
	
	public boolean userHasSession(String userName)
	{
		Iterator<UserSession> i = userSessions.iterator();
		while(i.hasNext())
		{
			UserSession s = i.next();
			if(s.getUserName().equals(userName))
				return true;
			
		}
		return false;
	}
	
	public Vector<UserSession> getUserSessions()
	{
		return userSessions;
	}

	public ArrayList<Socket> getClientRecords() {
		// TODO Auto-generated method stub
		return sockets;
	}
}
